package com.xiaodou.mjf.application.fee.manager;

import com.xiaodou.mjf.application.basic.utils.SequenceGenerator;
import com.xiaodou.mjf.application.core.service.AccountService;
import com.xiaodou.mjf.application.core.service.FinancingLoanService;
import com.xiaodou.mjf.application.core.service.FinancingService;
import com.xiaodou.mjf.application.core.service.FinancingStatisticsService;
import com.xiaodou.mjf.application.core.service.InvestService;
import com.xiaodou.mjf.application.core.service.LoanService;
import com.xiaodou.mjf.application.core.service.NotesBookService;
import com.xiaodou.mjf.application.fee.service.AccountFeeService;
import com.xiaodou.mjf.application.fee.service.LoanMasterService;
import com.xiaodou.mjf.application.fee.service.ProductServiceChargeService;
import com.xiaodou.mjf.application.fee.service.RepaymentPlanDefineService;
import com.xiaodou.mjf.application.fee.service.RepaymentPlanDetailService;
import com.xiaodou.mjf.application.fee.service.RepaymentPlanService;
import com.xiaodou.mjf.application.fee.service.ServeChargeCouponService;
import com.xiaodou.mjf.application.fee.service.ServeChargeService;
import com.xiaodou.mjf.application.fee.service.UnpaymentService;
import com.xiaodou.mjf.entity.core.Account;
import com.xiaodou.mjf.entity.core.Deposit;
import com.xiaodou.mjf.entity.core.Financing;
import com.xiaodou.mjf.entity.core.FinancingLoan;
import com.xiaodou.mjf.entity.core.FinancingStatistics;
import com.xiaodou.mjf.entity.core.Invest;
import com.xiaodou.mjf.entity.core.Loan;
import com.xiaodou.mjf.entity.core.NotesBook;
import com.xiaodou.mjf.entity.fee.AccountFee;
import com.xiaodou.mjf.entity.fee.LoanMaster;
import com.xiaodou.mjf.entity.fee.ProductServiceCharge;
import com.xiaodou.mjf.entity.fee.RepaymentPlan;
import com.xiaodou.mjf.entity.fee.RepaymentPlanDefine;
import com.xiaodou.mjf.entity.fee.RepaymentPlanDetail;
import com.xiaodou.mjf.entity.fee.ServeCharge;
import com.xiaodou.mjf.entity.fee.ServeChargeCoupon;
import com.xiaodou.mjf.entity.fee.Unpayment;
import com.xiaodou.mjf.infrastructure.common.context.SpringContextHolder;
import com.xiaodou.mjf.infrastructure.payeco.util.Base64;
import com.xiaodou.mjf.infrastructure.payeco.version2.MsgBean;
import com.xiaodou.mjf.infrastructure.payeco.version2.MsgBody;
import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.springframework.stereotype.Controller;

import javax.transaction.Transactional;
import java.util.Date;
import java.util.List;

/**
 * Created by Alvin on 2015/3/23.
 */
@Controller
@Transactional
public class FeeManager {
    private static Logger logger = Logger.getLogger(FeeManager.class.getName());

    private static ServeChargeService serveChargeService = SpringContextHolder.getBean(ServeChargeService.class);
    private static ServeChargeCouponService serveChargeCouponService = SpringContextHolder.getBean(ServeChargeCouponService.class);
    //满标计算
    private static FinancingService financingService = SpringContextHolder.getBean(FinancingService.class);
    private static FinancingStatisticsService financingStatisticsService = SpringContextHolder.getBean(FinancingStatisticsService.class);
    private static InvestService investService = SpringContextHolder.getBean(InvestService.class);

    //满标付款
    private static LoanService loanService = SpringContextHolder.getBean(LoanService.class);
    private static LoanMasterService loanMasterService = SpringContextHolder.getBean(LoanMasterService.class);
    private static RepaymentPlanDefineService repaymentPlanDefineService = SpringContextHolder.getBean(RepaymentPlanDefineService.class);
    private static RepaymentPlanService repaymentPlanService = SpringContextHolder.getBean(RepaymentPlanService.class);
    private static RepaymentPlanDetailService repaymentPlanDetailService = SpringContextHolder.getBean(RepaymentPlanDetailService.class);
    private static ProductServiceChargeService productServiceChargeService = SpringContextHolder.getBean(ProductServiceChargeService.class);
    private static FinancingLoanService financingLoanService = SpringContextHolder.getBean(FinancingLoanService.class);

    //生成账单
    private static AccountFeeService accountFeeService = SpringContextHolder.getBean(AccountFeeService.class);

    //还款
    private static AccountService accountService = SpringContextHolder.getBean(AccountService.class);
    private static NotesBookService notesBookService = SpringContextHolder.getBean(NotesBookService.class);

    //付息,还本
    private static UnpaymentService unpaymentService = SpringContextHolder.getBean(UnpaymentService.class);

    /**
     * 满标处理
     *
     * @param financingId 投资标的ID
     */
    public void calcFullScale(String financingId) {
        Financing financing = financingService.get(financingId);
        assert (null != financing) : "必须有对应的理财标的";

        FinancingStatistics financingStatistics = financingStatisticsService.findByfinanceId(financingId);
        assert (null != financingStatistics) : "必须有对应的理财标的统计";

        Double residualAmount = financingStatistics.getResidualAmount();
        if (0 != residualAmount) {
            // 结束处理
        } else {
            //⑤更改[理财标的表][字段：invest_status=1]，标识该标的满标；
            financing.setInvestStatus(1);
            financing.setPeriodsPayed(0);
            financingService.save(financing);

            List<Invest> investList = investService.findByFinanceId(financingId);
            for (Invest invest : investList) {
                invest.setFinanceStatus(1);
            }
            investService.save(investList);
        }
    }

    /**
     * 满标付款
     *
     * @param loanId 贷款申请ID
     */
    public void payFullScale(String loanId) {
        Loan loan = loanService.get(loanId);
        assert (null != loan) : "必须有对应的贷款申请";

        //生成贷款账号数据
        LoanMaster loanMasterBefore = new LoanMaster();
        loanMasterBefore.setLoanId(loanId);
        String accountNumber = SequenceGenerator.generateAccountNumber(SequenceGenerator.TYPE_LOAN_ACCOUNT);
        loanMasterBefore.setAccountNumber(accountNumber);
        String productId = loan.getProductId();
        loanMasterBefore.setProductId(productId);
        double loanAmount = loan.getLoanAmount();
        loanMasterBefore.setLoanAmount(loanAmount);
        loanMasterBefore.setMemberId(loan.getMemberId());
        LoanMaster loanMaster = loanMasterService.save(loanMasterBefore);

        //获取还款计划定义
        int term = loan.getTerm();
        RepaymentPlanDefine repaymentPlanDefine = repaymentPlanDefineService.findByProductIdAndTerm(productId, term);

        DateTime now = new DateTime();
        boolean first = true;
        DateTime stageDateTime = now;
        double installmentAmount = loanAmount / term;
        for (int i = 0; i < term; i++) {
            int stageNo = i + 1;
            if (!first) {
                stageDateTime = stageDateTime.plusMonths(1);
            }
            // 生成还款计划信息，根据分期数，每期生成一条记录
            RepaymentPlan repaymentPlan = new RepaymentPlan();
            repaymentPlan.setAccountNumber(accountNumber);
            repaymentPlan.setPlanDefineId(repaymentPlanDefine.getId());
            repaymentPlan.setPlanDefineName(repaymentPlanDefine.getName());
            repaymentPlan.setStageNo(stageNo);
            repaymentPlan.setStageStartTime(stageDateTime.toDate());
            repaymentPlan.setStageEndTime(stageDateTime.plusMonths(1).toDate());
            repaymentPlan.setStageTerm(stageNo);
            repaymentPlan.setRepaymentPrincipal(loanAmount);
            repaymentPlan.setArrearCapital(0.0);
            repaymentPlan.setInstallmentAmount(installmentAmount);
            repaymentPlan.setFirstInstallmentDate(now.toDate());
            repaymentPlan.setInstallmentNo(stageNo);
            repaymentPlan.setInstallmentFrequency(1);
            //repaymentPlan.setFirst
            repaymentPlan.setIoaRuleCode("1");
            repaymentPlan.setIoaRuleRate(0.5);
            repaymentPlan.setIoaFrequency(1);
            RepaymentPlan repaymentPlanAfter = repaymentPlanService.save(repaymentPlan);

            // 生成还款计划详情，根据分期数，每期生成一条记录
            RepaymentPlanDetail repaymentPlanDetail = new RepaymentPlanDetail();
            repaymentPlanDetail.setId(repaymentPlanAfter.getId());
            repaymentPlanDetail.setAccountNumber(accountNumber);
            repaymentPlanDetail.setStageNo(stageNo);
            repaymentPlanDetail.setStageStartTime(stageDateTime.toDate());
            repaymentPlanDetail.setStageEndTime(stageDateTime.plusMonths(1).toDate());
            repaymentPlanDetail.setInstallmentNo(stageNo);
            repaymentPlanDetail.setFirstInstallmentDate(now.toDate());
            repaymentPlanDetail.setPrincipalAmount(installmentAmount);
            double interestAmount = 0.0;//todo:根据product_service_charge配置计算
            ProductServiceCharge productServiceCharge = productServiceChargeService.findByProductId(productId);
            String serveChargeId = productServiceCharge.getServiceChargeId();
            ServeCharge serveCharge = serveChargeService.get(serveChargeId);
            double feeTmp = 0.0;
            //1、百分比2、固定值（RMB）
            Integer chargingType = serveCharge.getChargingType();
            //收取值
            Double chargingValue = serveCharge.getChargingValue();

            if (chargingType == 1) {//百分比
                feeTmp += installmentAmount * chargingValue;
            } else if (chargingType == 2) {//固定值（RMB）
                feeTmp += chargingValue;
            }

            //同一时间点有效的优惠最多有1个.
            ServeChargeCoupon serveChargeCoupon = serveChargeCouponService.findByServeChargeId(serveChargeId);

            if (null != serveChargeCoupon) {//有优惠
                //调整方式
                //1、打折调整（9折,8折）
                //2、百分点调整（负不超过手续费设置值）
                //3、固定值（RMB元最多减为0）
                Integer adjustType = serveChargeCoupon.getAdjustType();

                //具体调整值
                Double adjustRate = serveChargeCoupon.getAdjustRate();

                //CALC
                if (1 == adjustType) {//1、打折调整（9折,8折）
                    interestAmount += feeTmp * adjustRate;
                } else if (2 == adjustType) {//2、百分点调整（负不超过手续费设置值）
                    interestAmount += feeTmp * (1 - adjustRate / 100);
                } else if (3 == adjustType) {//3、固定值（RMB元最多减为0）
                    interestAmount += feeTmp - adjustRate;
                }
            }
            repaymentPlanDetail.setInterestAmount(interestAmount);
            double subsidyAmount = 0.0;
            repaymentPlanDetail.setSubsidyAmount(subsidyAmount);
            repaymentPlanDetail.setInstallmentDays(30);
            repaymentPlanDetail.setPrincipalBalance(loanAmount - (loanAmount / term) * stageNo);// loan_master:loan_amount – (loan_master:loan_amount / term) * stage_no
            repaymentPlanDetail.setTotalRepaymentAmount(installmentAmount + interestAmount + subsidyAmount);//principal_amount+interest_amount+subsidy_amount
            repaymentPlanDetail.setAmortizationInterest(0.0);
            repaymentPlanDetailService.save(repaymentPlanDetail);
            first = false;
        }
        //更新financing_loan
        FinancingLoan financingLoan = financingLoanService.findByLoanId(loanId);
        financingLoan.setInvestStatus(Financing.INVEST_STATUS_REPAYMENT);
        financingLoanService.save(financingLoan);
        //更新loan表
        loan.setFinanceStatus(Loan.LOAN_STATUS_REPAYMENT);
        loanService.save(loan);

        //TODO:调用代付接口，付款到loan对应商户账号：预留
        //TODO:目前没有商户账号
        String batchNo = SequenceGenerator.generateBatchPay("MJF");
    }

    /**
     * 账单生成
     */
    public void genOrder() {

        DateTime now = new DateTime();

        //1、	查询[表：loan][字段：finance_status=2][字段：status=0]，得出所有未结清贷款。
        List<Loan> loanList = loanService.findByFinanceStatusAndStatus(2, 0);

        // 2、	遍历未结清贷款，查询[表：loan_master][字段：loan_id=loan:id]，得到贷款账号。
        for (Loan loan : loanList) {
            String loanId = loan.getId();
            LoanMaster loanMaster = loanMasterService.findByLoanId(loanId);
            String accountNumber = loanMaster.getAccountNumber();
            //3、	查询[表：repayment_detail][字段：account_number=loan_master:account_number][字段：stage_end_time between 本月第一天0点 and 本月最后一天24点]，得到当前贷款账号当前期应还款。
            //只能查出一个
            RepaymentPlanDetail repaymentPlanDetail = repaymentPlanDetailService.findByAccountNumberAndStageEndTime(accountNumber);
            //4、	新建[表：account_fee]，生成当前贷款当期应还款。
            AccountFee accountFee = new AccountFee();
            accountFee.setMemberId(loan.getMemberId());
            accountFee.setAccountNumber(accountNumber);
            accountFee.setInstallmentNo(repaymentPlanDetail.getInstallmentNo());
            accountFee.setStageStartTime(repaymentPlanDetail.getStageStartTime());
            accountFee.setStageEndTime(repaymentPlanDetail.getStageEndTime());
            //[字段：repayment_date=留空，实际还款日期]
            accountFee.setInterestAmount(repaymentPlanDetail.getInterestAmount());
            accountFee.setArrearsAmount(repaymentPlanDetail.getTotalRepaymentAmount());
            accountFee.setYear(now.getYear());
            accountFee.setMonth(now.getMonthOfYear());
            //[字段：last_repayment_date=上次还款日期，留空]
            accountFee.setRepaymentStatus(1);
            accountFeeService.save(accountFee);
        }
    }

    /**
     * 还款
     *
     * @param memberId        会员ID
     * @param year            账单年
     * @param month           账单月
     * @param repaymentAmount 还款金额
     */
    public void payback(String memberId, int year, int month, double repaymentAmount) {
        DateTime now = new DateTime();
        List<AccountFee> accountFeeList = accountFeeService.findByMemberIdAndYearAndMonth(memberId, year, month, 1);
        double arrearsAmountSum = 0.0;
        for (AccountFee accountFee : accountFeeList) {
            Double arrearsAmount = accountFee.getArrearsAmount();
            if (null != arrearsAmount) {
                arrearsAmountSum += arrearsAmount;
            }
        }

        // 2、	比较{input:repaymentAmount}与上一步求和金额，不相等，退出。
        if (repaymentAmount != arrearsAmountSum) {
            return;
        }

        //3、	查询[表：account][member_id={input:memberId}]，得到存款账号。
        Account account = accountService.getInfoBymemberId(memberId);

        //4、	新建[表：deposit]，添加一条充值记录
        Deposit deposit = new Deposit();
        //[字段：serial_number=流水号，该方法需要编写，规则见下方]
        deposit.setSerialNumber(SequenceGenerator.generateNotesBook(SequenceGenerator.TYPE_NOTEBOOK, "10210001"));
        deposit.setMemberId(memberId);
        deposit.setAccountId(account.getId());
//        [字段：card_number=暂空]
//        [字段：account_title=暂空]
//        [字段：tran_channel_id=暂空]
//        [字段：tran_channel_response=暂空]
        deposit.setAmount(repaymentAmount);
        deposit.setFee(0.0);
        deposit.setPurpose(year + "年" + month + "月账单还款");
        deposit.setProcDate(now.toDate());
        deposit.setChannelId("10210001");
        //[字段：channel_serial=]

        //5、	新建[表：notes_book]，添加一条存款流水
        NotesBook notesBook = new NotesBook();
        notesBook.setAccount(account.getNumber());
        notesBook.setDescription("充值");
        notesBook.setDrcr("D");
        notesBook.setAmount(repaymentAmount);
        notesBook.setBalance(account.getBookBalance());
        //[字段：card_number=暂空]
        //[字段：serial_number=流水号，调用流水号生成方法]
        notesBook.setSerialNumber(SequenceGenerator.generateNotesBook(SequenceGenerator.TYPE_NOTEBOOK, "10210001"));
        //[字段：additional_text=交易附加信息，可为空]
        notesBook.setType(0);
        notesBook.setTxnDate(now.toDate());
//        [字段：auth_date=暂空]
//        [字段：proc_date=暂取当前时间，待支付联通取交易成功时间]
        notesBook.setProcDate(now.toDate());
        notesBookService.save(notesBook);

        //6、	新建[表：notes_book]，添加一条还款流水
        NotesBook notesBook2 = new NotesBook();
        notesBook2.setAccount(account.getNumber());
        notesBook2.setDescription(year + "年" + month + "月账单还款");
        notesBook2.setDrcr("C");
        notesBook2.setAmount(repaymentAmount);
        notesBook2.setBalance(account.getBookBalance());
        //[字段：card_number=暂空]
        //[字段：serial_number=流水号，调用流水号生成方法]
        notesBook2.setSerialNumber(SequenceGenerator.generateNotesBook(SequenceGenerator.TYPE_NOTEBOOK, "10210001"));
        //[字段：additional_text=交易附加信息，可为空]
        notesBook2.setType(5);
        notesBook2.setTxnDate(now.toDate());
//        [字段：auth_date=暂空]
//        [字段：proc_date=暂取当前时间，待支付联通取交易成功时间]
        notesBook2.setProcDate(now.toDate());
        notesBookService.save(notesBook2);

        //7、	遍历[表：account_fee][字段：member_id={input:memberId}][字段：year={input:year}][字段：month={input:month}]，得到当期待还款清单。
        for (AccountFee accountFee : accountFeeList) {
            List<RepaymentPlanDetail> repaymentPlanDetailList = repaymentPlanDetailService.findByAccountNumberAndInstallmentNo(account.getNumber(), accountFee.getInstallmentNo());
            for (RepaymentPlanDetail repaymentPlanDetail : repaymentPlanDetailList) {
                repaymentPlanDetail.setRepaymentPrincipalDate(now.toDate());
                repaymentPlanDetail.setRepaymentInterestDate(now.toDate());
            }
            //8、	更新[表：repayment_plan_detail]，设置还款时间
            repaymentPlanDetailService.save(repaymentPlanDetailList);

            accountFee.setRepaymentDate(now.toDate());
            accountFee.setArrearsAmount(0.0);
            accountFee.setRepaymentStatus(0);
        }
        //9、	更新[表：account_fee]，设置还款数据
        accountFeeService.save(accountFeeList);
    }

    /**
     * 付息
     */
    public void interest() {

        DateTime now = new DateTime();

        //遍历所有还款中的理财标的
        List<Financing> financingList = financingService.getFinancingListByStatus(2);


        for (Financing financing : financingList) {
            String financeId = financing.getId();
            //是否付息日
            Date nextRepaymentDate = financing.getNextRepaymentDate();
            DateTime tmpDt = new DateTime(nextRepaymentDate);
            if (now.getYear() == tmpDt.getYear() && now.getMonthOfYear() == tmpDt.getMonthOfYear() && now.getDayOfMonth() == tmpDt.getDayOfMonth()) {

                //计算利息
                //待付利息=年华收益率/100/12*本金(invest.amount)
                double minProfitRate = financing.getMinProfitRate();
                double profitRate = minProfitRate / 100 / 12;
                List<Invest> investList = investService.findByFinanceId(financeId);
                for (Invest invest : investList) {
                    double amount = invest.getAmount();
                    String memberId = invest.getMemberId();

                    double profit = profitRate * amount;
                    //生成待付利息表
                    Unpayment unpayment = new Unpayment();
                    unpayment.setType(0);
                    unpayment.setFinancingId(financeId);
                    unpayment.setMemberId(memberId);
                    unpayment.setAmount(profit);
                    unpayment.setPeriodNo(financing.getPeriodsPayed() + 1);
                    unpayment.setDueDate(now.toDate());
                    unpaymentService.save(unpayment);
                }


            }

        }
    }

    /**
     * TODO:还本
     */
    public void capital() {

        DateTime now = new DateTime();

        //遍历所有还款中的理财标的
        List<Financing> financingList = financingService.getFinancingListByStatus(2);


        for (Financing financing : financingList) {
            String financeId = financing.getId();
            //是否还本日
            Date lastRepaymentDate = financing.getLastRepaymentDate();
            DateTime tmpDt = new DateTime(lastRepaymentDate);
            if (now.getYear() == tmpDt.getYear() && now.getMonthOfYear() == tmpDt.getMonthOfYear() && now.getDayOfMonth() == tmpDt.getDayOfMonth()) {

                //计算利息
                //待还本金=本金(invest.amount)
                List<Invest> investList = investService.findByFinanceId(financeId);
                for (Invest invest : investList) {
                    double amount = invest.getAmount();
                    String memberId = invest.getMemberId();

                    //生成待还本金表
                    Unpayment unpayment = new Unpayment();
                    unpayment.setType(1);
                    unpayment.setFinancingId(financeId);
                    unpayment.setMemberId(memberId);
                    unpayment.setAmount(amount);
                    unpayment.setDueDate(now.toDate());
                    unpaymentService.save(unpayment);
                }
            }

        }


    }

    /**
     * 清理未付款投标记录
     */
    public void cleanUnpay() {

        List<Invest> investList = investService.findByPaymentStatusAndStatus(1, 0);
        for (Invest invest : investList) {
            //1、遍历状态正常且未付款投标记录，将记录状态设置为已失效
            invest.setStatus(1);
            investService.save(invest);

            //2、复位可购买份数
            FinancingStatistics financingStatistics = financingStatisticsService.findByfinanceId(invest.getFinanceId());
            int type = invest.getType();
            int count = financingStatistics.getCount();
            --count;
            financingStatistics.setCount(count);
            if (1 == type) {//美丽理财
                int residualCount = financingStatistics.getResidualCount();
                ++residualCount;
                financingStatistics.setResidualCount(residualCount);
            } else if (2 == type) {//小豆理财
                double residualAmount = financingStatistics.getResidualAmount();
                double amount = invest.getAmount();
                residualAmount += amount;
                financingStatistics.setResidualAmount(residualAmount);
            }
            financingStatisticsService.save(financingStatistics);
        }


    }

}
